#include "ofApp.h"


/*

 This example demonstrates a simple game. We have a GameEvent class that is
 used to store the bullet and bug that just collided.


 Topics:
 ofEventArgs
 ofAddListener
 ofRemove
 vector math
 objects & classes

 by: Todd Vanderlin

 */

//--------------------------------------------------------------
bool ofApp::shouldRemoveBullet(Bullet &b) {

	if(b.bRemove) return true;


	bool bRemove = false;

	// get the rectangle of the OF world
	ofRectangle rec = ofGetCurrentViewport();

	// check if the bullet is inside the world
	if(rec.inside(b.pos) == false) {
		bRemove = true;
	}



	return bRemove;
}

//--------------------------------------------------------------
bool ofApp::shouldRemoveBug(Bug &b) {
	return b.bRemove;
}

//--------------------------------------------------------------
void ofApp::setup() {

	ofBackgroundHex(0xc5c9b2);
	ofSetFrameRate(60);

	bFire = false;
	bugsKilled = 0;
	maxBullets = 30;

	// add some random holes for the bugs to come out
	int nHoldes = 10;
	for(int i=0; i<nHoldes; i++) {
		glm::vec2 p(ofRandomWidth(), ofRandomHeight());
		holes.push_back(p);
	}

	// listen to any of the events for the game
	ofAddListener(GameEvent::events, this, &ofApp::gameEvent);

}

//--------------------------------------------------------------
void ofApp::gameEvent(GameEvent &e) {

	cout << "Game Event: "+e.message << endl;
	e.bug->timeBugKilled = ofGetElapsedTimef();
	e.bug->bSquashed = true;

	e.bullet->bRemove = true;

	bugsKilled ++;
}

//--------------------------------------------------------------
void ofApp::update() {

	if((int)ofRandom(0, 20)==10) {

		int randomHole = ofRandom(holes.size());

		Bug newBug;
		newBug.pos = holes[randomHole];
		newBug.vel = glm::vec2(ofRandom(-1, 1), ofRandom(-1, 1));
		bugs.push_back(newBug);
	}

	for(unsigned int i=0; i<bugs.size(); i++) {

		bugs[i].update();

		// bug pos and size
		float   size = bugs[i].size;
		glm::vec2 pos  = bugs[i].pos;

		// wrap the bugs around the screen
		if(pos.x > ofGetWidth()-size)  bugs[i].pos.x = -size;
		if(pos.x < -size)              bugs[i].pos.x = ofGetWidth()-size;
		if(pos.y > ofGetHeight()+size) bugs[i].pos.y = -size;
		if(pos.y < -size)              bugs[i].pos.y = ofGetHeight()-size;

	}

	// check if we should remove any bugs
	ofRemove(bugs, shouldRemoveBug);

	// update the bullets
	for(unsigned int i=0; i<bullets.size(); i++) {
		bullets[i].update();
	}

	// check if we want to remove the bullet
	ofRemove(bullets, shouldRemoveBullet);


	// did we hit a bug loop we are checking to see if a bullet
	// hits a bug. if so we are going to launch an event for the game
	for(unsigned int i=0; i<bullets.size(); i++) {
		for(unsigned int j=0; j<bugs.size(); j++) {

			glm::vec2 a       = bullets[i].pos;
			glm::vec2 b       = bugs[j].pos;
			float   minSize = bugs[j].size;

			if(glm::distance(a,b) < minSize) {

				static GameEvent newEvent;
				newEvent.message = "BUG HIT";
				newEvent.bug     = &bugs[j];
				newEvent.bullet  = &bullets[i];

				ofNotifyEvent(GameEvent::events, newEvent);
			}

		}
	}


}

//--------------------------------------------------------------
void ofApp::draw(){

	// draw the bug holes
	for(unsigned int i=0; i<holes.size(); i++) {
		ofSetColor(100);
		ofDrawCircle(holes[i], 10);
		ofSetColor(40);
		ofDrawCircle(holes[i], 7);
	}

	for(unsigned int i=0; i<bugs.size(); i++) {
		bugs[i].draw();
	}

	// draw the bullets
	for(unsigned int i=0; i<bullets.size(); i++) {
		bullets[i].draw();
	}



	// game stats
	ofSetColor(10);
	ofDrawBitmapString("Bullets "+ofToString(bullets.size())+"\nBugs Killed: "+ofToString(bugsKilled), 20, 20);


	// gun
	glm::vec2 gunPos(ofGetWidth()/2, ofGetHeight()-20);
	glm::vec2 mousePos(ofGetMouseX(), ofGetMouseY());

	// get the vector from the mouse to gun
	glm::vec2 vec = normalize(mousePos - gunPos);
	vec *= 100;

	// get the angle of the vector for rotating the rect
	float angle = ofRadToDeg(atan2(vec.y, vec.x)) - 90;

	ofPushMatrix();
	ofTranslate(gunPos.x, gunPos.y);
	ofRotateZDeg(angle);

	ofFill();
	ofSetColor(10);
	ofDrawRectangle(-10, 0, 20, 100);

	float bulletPct = ofMap(bullets.size(), 0, maxBullets, 0.0, 100.0);
	ofSetColor(100);
	ofDrawRectangle(-10, 0, 20, bulletPct);

	ofSetColor(100);
	ofDrawRectangle(-10, 90, 20, 10);

	if(bFire) {
		ofSetColor(220, 0, 0);
		ofDrawRectangle(-10, 97, 20, 3);
	}
	ofPopMatrix();

	ofSetColor(255);
	ofDrawCircle(gunPos.x, gunPos.y, 2);

}

//--------------------------------------------------------------
void ofApp::keyPressed(int key) {
	if(key == ' ') {
		if(bullets.size() < maxBullets) {
			bFire = true;

			Bullet b;

			// the two points for the mouse and gun
			glm::vec2 gunPt(ofGetWidth()/2, ofGetHeight()-20);
			glm::vec2 mousePt(ofGetMouseX(), ofGetMouseY());

			// the vector between the two, and normalized = 0.0 - 1.0
			glm::vec2 vec = glm::normalize(mousePt - gunPt);

			// bullet position = the start pos of the gun
			// and the vec scaled by 100
			glm::vec2 bulletPos = gunPt + (vec * 100);

			b.pos     = bulletPos;
			b.vel     = vec * ofRandom(9, 12); // randomly make it faster
			b.bRemove = false;

			// add the bullets to the array
			bullets.push_back(b);
		}
	}
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key) {
	bFire = false;
}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
